<?php

namespace common\models\db;

use adminApi\modules\rbac\models\Permissions;
use Carbon\Carbon;
use common\components\wtools\tools\ArrayHelper;
use common\components\wtools\tools\Security;
use common\datas\Enums;
use common\Tools;
use Yii;
use yii\behaviors\BlameableBehavior;
use yii\behaviors\TimestampBehavior;

/**
 * This is the model class for table "{{%adminers}}".
 *
 * @author
 * @property RoleHasModels[] $roleHasModels
 * @property Roles[] $roles
 * @property array $permissionPaths
 * @property-read array $safeShow
 */
class Adminers extends \common\models\db\tables\Adminers
{
    const SCENARIO_TEST = 'test';

    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors = ArrayHelper::merge($behaviors, [
            'timestamp' => [
                'class' => TimestampBehavior::class,
//                'createdAtAttribute' => false,
//                'updatedAtAttribute' => false,
            ],
            'blameable' => [
                'class' => BlameableBehavior::class,
                'createdByAttribute' => false,
                'updatedByAttribute' => false,
            ],
        ]);
        return $behaviors;
    }

    public function attributeLabels()
    {
        $attributeLabels = parent::attributeLabels();
        $attributeLabels = ArrayHelper::merge($attributeLabels, []);
        return $attributeLabels;
    }

    public function rules()
    {
        $rules = parent::rules();
        foreach ($rules as $k => $v) {
            if ($v[1] == 'required'){
                $rules[$k][0] = array_diff($rules[$k][0], ['created_at', 'updated_at']);
            }
        }
        $rules = ArrayHelper::merge($rules, [
//            [[], 'required', 'on' => self::SCENARIO_TEST],
        ]);
        return $rules;
    }

    public function scenarios()
    {
        $scenarios = parent::scenarios();
        $scenarios = ArrayHelper::merge($scenarios, [
            self::SCENARIO_TEST => [],
        ]);
        return $scenarios;
    }


    /**
     * @return false|mixed|Adminers[]
     */
    public static function getAllWithCache()
    {
        return Yii::$app->cache->getOrSet("db-Adminers-getAllWithCache", function () {
            return static::find()->all();
        }, null);
    }

    /**
     * @param $id
     * @return false|Adminers|mixed
     */
    public static function getByIdWithCache($id)
    {
        return Yii::$app->cache->getOrSet("db-Adminers-getByIdWithCache/{$id}", function () use ($id) {
            return static::findOne($id);
        }, null);
    }

    public function deleteCaches()
    {
        Yii::$app->cache->delete("db-Adminers-getAllWithCache");
        Yii::$app->cache->delete("db-Adminers-getByIdWithCache/{$this->id}");
    }

    public function afterSave($insert, $changedAttributes)
    {
        parent::afterSave($insert, $changedAttributes);
        $this->deleteCaches();
    }

    public function afterRefresh()
    {
        parent::afterRefresh();
        $this->deleteCaches();
    }

    public function afterDelete()
    {
        parent::afterDelete();
        $this->deleteCaches();
    }


    # relations

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getRoleHasModels()
    {
        return $this->hasMany(RoleHasModels::class, ['model_id' => 'id'])->where(['model_type' => RoleHasModels::MODEL_TYPE_ADMINERS]);
    }

    /**
     * @return \yii\db\ActiveQuery
     * @throws \yii\base\InvalidConfigException
     */
    public function getRoles()
    {
        return $this->hasMany(Roles::class, ['id' => 'role_id'])->viaTable(RoleHasModels::tableName(), ['model_id' => 'id'], function ($q) {
            $q->andWhere(['model_type' => RoleHasModels::MODEL_TYPE_ADMINERS]);
        });
    }

    /**
     * @return array
     */
    public function getPermissionPaths()
    {
        $arr = [];
        if ($this->is_super == Enums::YES) {
            foreach (Permissions::getAllWithCache() as $k => $v) {
                $arr[] = $v->path;
            }
        } else {
            foreach ($this->roles as $role) {
                foreach ($role->permissions as $permission) {
                    if (!in_array($permission->path, $arr)) $arr[] = $permission->path;
                }
            }
        }
        return $arr;
    }

    # static funs

    public function test()
    {
        $test = self::instance();
        $test->setScenario(self::SCENARIO_TEST);
        $test->save();
        var_dump($test->toArray());
    }

    # funs

    /**
     * @return void
     * @throws \yii\base\Exception
     */
    public function generateToken()
    {
        $token = Tools::generateHasDateUniqueString();
        if (static::findOne(['token' => $token])) {
            $token = Tools::generateHasDateUniqueString();
        }
        $this->token = $token;
        $this->key = Tools::generateRandomStr();
    }

    /**
     * @param $password
     * @return void
     */
    public function generatePassword($password)
    {
        $this->password = md5($password);
        $this->pwd_back = Security::thinkEncrypt($password);
    }

    /**
     * @param string $password
     * @return bool
     */
    public function validatePassword($password)
    {
        return $password == md5($this->password);
    }

    public function generateJwtTokenData($authDuration = null)
    {
        $created_at = Carbon::now()->timestamp;
        $jwtParams = \Yii::$app->params['jwt']['adminApi'];
        if ($authDuration) {
            $end_at = $created_at + $authDuration;
        } else {
            $end_at = $created_at + $jwtParams['authDuration'] ?? 3600;
        }
        $token = Security::thinkEncrypt($this->token.$created_at, $jwtParams['jwtThinkKey']);
        $key = md5($this->key.$created_at);
        $jwtArr = [
            'header' => [
                'typ' => 'JWT',
                'alg' => 'HS256',
            ],
            'payload' => [
                'created_at' => $created_at,
                'end_at' => $end_at,
                'token' => $token,
            ],
        ];
        $header = Tools::toJson($jwtArr['header']);
        $header = base64_encode($header);
        $payload = Tools::toJson($jwtArr['payload']);
        $payload = base64_encode($payload);
        $signature = md5($header.'.'.$payload.'.'.$this->key);
        $jwtToken = $header.'.'.$payload.'.'.$signature;
        return [
            'token' => $jwtToken,
            'key' => $key,
        ];
    }

    public static function getSafeShowAttrs()
    {
        return ['id', 'status', 'created_at', 'updated_at', 'mobile', 'is_super', 'account_name'];
    }

    /**
     * @return array
     */
    public function getSafeShow()
    {
        return ArrayHelper::filter($this->toArray(), static::getSafeShowAttrs());
    }
}
